<?php
/*
 File :           ConfFile.php
 Name :           Class for manipulation with "Conf-File ver. (0.11)"
 Version :        1.2
 Release :        30. 1. 2007
 Descript :       Class for manipulation with "Conf-File ver. (0.11)"

 ------------------ Conf-File ver (0.11) definition -------------
 [<block1>]
 <key1>=<value1>
 <key1>=<value2>
 <key2>=<value3>
 .       .

 [<block2>]
 <key1>=<valueX>
 .       .
 ----------------------------------------------------------------
 Note: First (1) and last line are reserved for secure file by
 php interpret.

 Functions:

 public function GetData()                      -> returns ConfFile::Data - array generated
 from Conf file.

 Struct:
 ConfFile::Data[<block>][<key>][<0..N>]=<value>

 public function Open($filename)                -> Use for opening Conf file
 - if object was build with parameter, you don't need
 use this function
 Example:
 $tmp = new ConfFile("file.conf");
 is equivalent of:
 $tmp = new ConfFile();
 $tmp->Open("file.conf")

 public function Close()                         -> Use for close file
 - If destroy object by delete You DON'T need close file before.

 public function Load()                          -> Load Conf file (file musst be opened)
 returns ConfFile::Data

 private function Save()                         -> Save/convert ConfFile::Data into opened file


 ////////// Function for data manipulation \\\\\\\\\\\\\
 public function AddItem($block,$parametr,$value)
 public function EditItem($block, $item, $index, $new_value)
 public function DeleteItem($block, $item, $index)

 ////////// Function for blocks manipulation \\\\\\\\\\\\
 public function AddBlock($block)
 public function DeleteBlock($block)
 public function RenameBlock($block, $newblock)
 */

class ConfFile
{
  protected $File;
  protected $Data=array();

  function __construct($filename="n/a")
  {
    if ($filename!= "n/a") {$this->Open($filename);}
  }

  function __destruct()
  {
    if ($this->File){$this->Close();}
  }

  public function GetData()                              /* returns ConfFile::Data */
  {
    return $this->Data;
  }

  public function Open($filename)                        /* openi file */
  {
    if(file_exists($filename))
    {
      $this->File=@FOpen($filename, 'r+');
      return (!($this->File==false));
    }
    else {return false;}
  }

  public function Close()                                /* close file */
  {
    return (@FClose($this->File));
  }

  public function Reload()
  {
    $this->Close();
    $this->Open();
    return $this->Load();
  }
  
  public function Load()                                 /* read file to ConfFile::Data and returns updated ConfFile::Data */
  {
    rewind($this->File);        // move pointer to 1st position
    if ($this->File)
    {
      $this->Data = array();
      $line_count=1;
      while (!feof($this->File))
      {
        $line = FGetS($this->File, 4096);
        if ($line_count>1)
        {
          if (!eregi("^[ ]*\[(.+)\]", $line, $user))
          {
            if (eregi("^[ ]*([^=]+)[ ]*=[ ]*(.+)[ ]*[\n]", $line, $parametr))
            {
              if(!ereg('^;.*',$parametr[1]))
              {
                $porad_cislo=0;
                while (isset($this->Data[$user[1]][$parametr[1]][$porad_cislo])) {$porad_cislo++; }
                $this->Data[$user[1]][$parametr[1]][$porad_cislo]=trim($parametr[2]);
              }
            }
          }
        }
        $line_count++;
      }
      return $this->Data;
    }
    else {return false;}
  }


  public function Save()
  {
    if ($this->File!=false)
    {
      rewind($this->File);	// Seek to position	0
      $newfile=array();
      $savedkeys=array();
      $savedblocks=array();
      $block=false;
      $item=false;
      do
      {
        $line=fgets($this->File);
        $newfile[]=rtrim($line);
      }
      while((!feof($this->File)) and (!ereg('^[ ]*\[(.*)\]',$line,$tmp)));
      if (!feof($this->File))
      {
        $block=$tmp[1];		// name of first block
        $line=@fgets($this->File);
        $savedblocks[]=$block;
        while(!feof($this->File))
        {
          if (!isset($this->Data[$block])) // this block was deleted
          {
            // delete last line in new file
            array_pop($newfile);
            do // move to next block
            {
              $line=fgets($this->File);
            }while((!feof($this->File)) and (!ereg('^[ ]*\[(.*)\]',$line,$tmp)));
            $block=$tmp[1];
            $savedkeys=array();
            $savedblocks[]=$block;
          }
          elseif(ereg('^([^=]+)[ ]*=[ ]*(.+)[ ]*[\n]?',$line,$tmp)) //attribut
          {
            if(array_key_exists($tmp[1], $this->Data[$block]))
            {
              // this atribut stays
              $newfile[]=rtrim($tmp[0]);		// copy line
              $savedkeys[]=rtrim($tmp[1]).'='.rtrim($tmp[2]);
            }
          }
          elseif(ereg('^[ ]*\[(.*)\]',$line,$tmp)) // block
          {
            // check if all attributes are saved
            //print_r($tmp);
            foreach ($this->Data[$block] as $key=>$varr)
            {
              foreach ($varr as $val){
                if (!in_array($key.'='.$val,$savedkeys))
                {
                  // this is a new attribut in existing block
                  $newfile[]=$key.'='.$val;

                }
              }
            }
            $newfile[]=rtrim($line);
            //print_r($savedblocks);
            //print_r($savedkeys);
            //echo "\n".$line."\n";
            $savedkeys=array();
            $block=$tmp[1];
            $savedblocks[]=$block;
          }
          else {
            $newfile[]=rtrim($line);
          }
          $line=@fgets($this->File);
        }
        // check, if some new attribut are added in last block
        foreach ($this->Data[$block] as $key=>$varr)
        {
          foreach ($varr as $val){
            if (!in_array($key.'='.$val,$savedkeys))
            {
              // this is a new attribut in existing block
              $newfile[]=$key.'='.$val;
            }
          }
        }
        // check, if some new block are added
        foreach ($this->Data as $block=>$tmp)
        {
          if (!in_array($block,$savedblocks))
          {
            // new block
            $newfile[] = '';
            $newfile[]='['.$block.']';
            foreach ($this->Data[$block] as $key=>$varr)
            {
              foreach ($varr as $val) $newfile[]=rtrim($key.'='.$val);
            }
          }
        }
      }
      // all lines are saved in $newfile - save $newfile lines into file
      fseek($this->File,0);
      ftruncate($this->File,0);	// clear file
      foreach ($newfile as $val)
      {
        fputs($this->File,$val."\n");
      }
      fputs($this->File,"*/?>");
      return true;
    }
    else return false;
  }
  public function AddItem($block,$parametr,$value)       /* New Item (block,key,value)*/
  {
    if (isset($this->Data[$block])) //overi jestli block existuje
    {
      $porad_cislo=0;
      while (isset($this->Data[$block][$parametr][$porad_cislo]))
      {
        $porad_cislo++;
      }
      $this->Data[$block][$parametr][$porad_cislo]=$value;
      print_r($this->Data[$block][$parametr]);
      $this->Save();
    }
    else {return false;}
  }

  public function EditItem($block, $item, $index, $new_value)
  {
    if (isset($this->Data[$block][$item][$index])) //overi jestli je co upravovat
    {
      $this->Data[$block][$item][$index]=$new_value;
      $this->Save();
    }
    else {return false;}
  }

  public function DeleteItem($block, $item, $index)
  {
    if (isset($this->Data[$block][$item][$index]))
    {
      unset($this->Data[$block][$item][$index]);
      $this->Save();
    }
    else {return false;}
  }

  public function AddBlock($block)                       /* new Block */
  {
    if (!isset($this->Data[$block]))
    {
      $this->Data[$block]=array();
      $this->Save();
    }
    else {return false;}
  }

  public function DeleteBlock($block)
  {
    if (isset($this->Data[$block])) //overi jestli block existuje
    {
      unset($this->Data[$block]);
      $this->Save();
    }
    else {return false;}
  }

  public function RenameBlock($block, $newblock)
  {
    if (isset($this->Data[$block])) //overi jestli block ktery se ma renamovat existuje
    {
      if (!isset($this->Data[$newblock])) //overi jestli neni novej nazev uz obsazenej
      {
        $this->Data[$newblock]=$this->Data[$block];
        unset($this->Data[$block]);
        $this->Save();
      }
      else {return false;}
    }
    else {return false;}
  }
}
?>